package gdt.entity;

import gdt.entity.AbstractSecureEntity;
import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;

import javax.persistence.*;

import org.hibernate.annotations.NamedQueries;
import org.hibernate.annotations.NamedQuery;
import org.hibernate.validator.NotEmpty;

import static javax.persistence.FetchType.LAZY;
import static javax.persistence.CascadeType.ALL;

/**
 * Entity that represents a category of tasks within a project.
 * It is compound of tasks.
 * A hierarchy of categories can be made, so each category
 * can have a parent category and a list of children categories.
 */
@NamedQueries({
	@NamedQuery(name="findCategoryByProjectAndName",query="select c from Category c where c.parentProject = :project and c.name like :name"),
	@NamedQuery(name="findCategoryByCategoryAndName",query="select c from Category c where c.parent = :category and c.name like :name")
})
@Entity
public class Category extends AbstractSecureEntity implements Serializable {

	private static final long serialVersionUID = 1L;
	
	@NotEmpty
	private String name;

	private String description;
	
	@ManyToOne(fetch=LAZY)
	private Project parentProject;
	
	@OneToMany(fetch=LAZY, mappedBy = "parent", cascade = ALL)
	private List<Category> children = new LinkedList<Category>();
	
	@ManyToOne(fetch=LAZY)
	private Category parent;
	
	@OneToMany(fetch=LAZY, mappedBy = "category", cascade = ALL)
	private List<Task> tasks = new LinkedList<Task>();

	
	public Category() {
		super();
	}   
	
	// ********************** Accessor Methods ********************** //
	
	public String getName() {
		return this.name;
	}

	public void setName(String name) {
		this.name = name;
	}   
	public String getDescription() {
		return this.description;
	}

	public void setDescription(String description) {
		this.description = description;
	}
	public void setParentProject(Project parentProject) {
		this.parentProject = parentProject;
	}
	public Project getParentProject() {
		return parentProject;
	}
	public void setChildren(List<Category> children) {
		this.children = children;
	}
	public List<Category> getChildren() {
		return children;
	}
	public void setParent(Category parent) {
		this.parent = parent;
	}
	public Category getParent() {
		return parent;
	}
	public void setTasks(List<Task> tasks) {
		this.tasks = tasks;
	}
	public List<Task> getTasks() {
		return tasks;
	}
	
	public long getMinutesWorked(){
		long minutes = 0;
		for(Category subCategory : children){
			minutes += subCategory.getMinutesWorked();
		}
		for(Task task : tasks){
			minutes += task.getDuration();
		}
		return minutes;
	}

	public List<Task> getAllTasks(){
		List<Task> tasks = new LinkedList<Task>();
		tasks.addAll(getTasks());
		for(Category c : getChildren()){
			tasks.addAll(c.getAllTasks());
		}
		return tasks;
	}
	
	// *********************** Adder Methods *********************** //
	
	public void addTask(Task task){
		this.tasks.add(task);
		task.setCategory(this);
	}
	
	public void addCategory(Category category){
		this.children.add(category);
		category.setParent(this);
	}
	
	
	// *********************** Remover Methods *********************** //
	
	public void removeTask(Task task){
		this.tasks.remove(task);
	}
	
	public void removeCategory(Category category){
		this.children.remove(category);
	}
}
